/*
 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//! CHECKER             Ecma builtins inlining. Must deoptimize if actual was function changed.
//! RUN                 options: "--compiler-regex=_GLOBAL::profiling_sin", entry: "_GLOBAL::func_main_0"
//! METHOD              "profiling_sin"
//! EVENT               /Compilation.*profiling_sin.*COMPILED/
//! PASS_AFTER          "InlineIntrinsics"
//! INST                "HclassCheck"
//! INST_NEXT           "LoadImmediate"
//! INST_NEXT           "LoadObject"
//! INST_NEXT           "Compare NE"
//! INST_NEXT           "DeoptimizeIf INLINE_DYN"
//! INST_NEXT           "AnyTypeCheck ECMASCRIPT_DOUBLE_TYPE"
//! INST_NEXT           "CastAnyTypeValue ECMASCRIPT_DOUBLE_TYPE"
//! INST_NEXT_NOT       "Cast "
//! INST_NEXT           "Intrinsic.MathSinF64"
//! EVENT_NEXT_NOT      /DeoptimizationReason,.*,DOUBLE_WITH_INT/
//! EVENT_NEXT_NOT      /DeoptimizationReason,.*,NOT_SMALL_INT/
//! EVENT_NEXT          /DeoptimizationReason,.*,INLINE_DYN/
//! EVENT_NEXT          /Compilation.*profiling_sin.*COMPILED/
//! PASS_AFTER_NEXT     "InlineIntrinsics"
//! INST                "HclassCheck"
//! INST_NEXT_NOT       "LoadImmediate"
//! INST_NEXT_NOT       "LoadObject"
//! INST_NEXT_NOT       "Compare NE"
//! INST_NEXT_NOT       "DeoptimizeIf INLINE_DYN"
//! INST_NEXT_NOT       "Intrinsic.MathSinF64"
//! INST_NEXT           "CallDynamic"
//! EVENT_NEXT_NOT      /Deoptimization/
//! EVENT_NEXT_NOT      /Compilation/


var func_holder = Math.sin;

function profiling_sin(arg)
{
    let saved_arg = arg;
    // Increment is necessary to profile the type:
    let res = func_holder(arg++);
    arg = saved_arg;
    return res;
}

function profile(arg)
{
    let lhs = func_holder(arg);
    let rhs = profiling_sin(arg);
    if (lhs != rhs) {
        throw "Wrong result " + lhs + " " + rhs;
    }
};

function check(arg)
{
    let lhs = func_holder(arg);
    let rhs = profiling_sin(arg);
    if (lhs != rhs) {
        throw "Wrong result " + lhs + " " + rhs;
    }
    RuntimeTesting.OptimizeFunctionOnNextCall(profiling_sin);
    lhs = func_holder(arg);
    rhs = profiling_sin(arg);
    if (lhs != rhs) {
        throw "Wrong result " + lhs + " " + rhs;
    }
};

RuntimeTesting.PrepareFunctionForOptimization(profiling_sin);

// Profile as double_with_int:
profile(3.1);
profile(3);
// Optimization:
check(3.1);
check(3);
// Deoptimization:
func_holder = Math.cos;;
check(3.1);
check(3);
